#include <errno.h>
#include <linux/netlink.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#define NETLINK_TEST 30   // 自定义协议
#define MSG_LEN      125  // 消息长度
#define MAX_PLOAD    125

typedef struct _user_msg_info {
    struct nlmsghdr hdr;
    char            pyload[MSG_LEN];
} user_msg_info;

int main(int argc, char** argv)
{
    char* msg = "hello netlink!!";

    /* 创建NETLINK socket */
    int sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
    if (sockfd == -1) {
        perror("create socket error\n");
        return -1;
    }

    struct sockaddr_nl src_addr;
    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;  // AF_NETLINK
    src_addr.nl_pid    = 100;         //端口号(port ID)
    src_addr.nl_groups = 0;
    if (bind(sockfd, (struct sockaddr*)&src_addr, sizeof(src_addr)) != 0) {
        perror("bind() error\n");
        close(sockfd);
        return -1;
    }

    struct sockaddr_nl dest_addr;
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.nl_family = AF_NETLINK;
    dest_addr.nl_pid    = 0;  // to kernel
    dest_addr.nl_groups = 0;

    user_msg_info u_info;
    memset(&u_info, 0, sizeof(u_info));
    u_info.hdr.nlmsg_flags = 0;
    u_info.hdr.nlmsg_len   = NLMSG_SPACE(MAX_PLOAD);
    u_info.hdr.nlmsg_pid   = src_addr.nl_pid;
    u_info.hdr.nlmsg_seq   = 0;
    u_info.hdr.nlmsg_type  = 0;

    memcpy(NLMSG_DATA(&u_info.hdr), msg, strlen(msg));
    int ret = sendto(sockfd, &u_info.hdr, u_info.hdr.nlmsg_len, 0,
                     (struct sockaddr*)&dest_addr, sizeof(struct sockaddr_nl));
    if (!ret) {
        perror("sendto error\n");
        close(sockfd);
        exit(-1);
    }
    printf("send kernel:%s\n", msg);

    char buf[MAX_PLOAD];

    // memset(&u_info, 0, sizeof(u_info));
    socklen_t len = sizeof(struct sockaddr_nl);
    ret           = recvfrom(sockfd, &u_info, sizeof(user_msg_info), 0,
                   (struct sockaddr*)&dest_addr, &len);
    if (!ret) {
        perror("recv form kernel error\n");
        close(sockfd);
        exit(-1);
    }

    printf("from kernel:%s\n", u_info.pyload);
    // printf("from kernel:%s\n", buf);

    close(sockfd);
    return 0;
}
